package com.wiscamp.ninechapters.problems.application.services;

import com.wiscamp.ninechapters.problems.application.assemblers.ProblemTypeAssembler;
import com.wiscamp.ninechapters.problems.application.assemblers.QuestionTypeAssembler;
import com.wiscamp.ninechapters.problems.application.dto.commands.types.BindTypeRelationCommand;
import com.wiscamp.ninechapters.problems.application.dto.commands.types.CreateProblemTypeCommand;
import com.wiscamp.ninechapters.problems.application.dto.commands.types.UnbindTypeRelationCommand;
import com.wiscamp.ninechapters.problems.application.dto.commands.types.UpdateProblemTypeCommand;
import com.wiscamp.ninechapters.problems.application.dto.vo.types.ProblemTypeVO;
import com.wiscamp.ninechapters.problems.application.dto.vo.types.QuestionTypeVO;
import com.wiscamp.ninechapters.problems.domain.repositories.ProblemTypeRepository;
import com.wiscamp.ninechapters.problems.domain.services.ProblemTypeService;
import cube.ddd.application.BaseAppService;
import cube.ddd.application.command.DeleteCommand;
import cube.ddd.application.command.DisableCommand;
import cube.ddd.application.command.EnableCommand;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.utils.AppServiceUtils;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Service;

import java.util.Collection;

@Service
public class ProblemTypeAppService extends BaseAppService {

    private final ProblemTypeRepository problemTypeRepository;

    private final ProblemTypeService problemTypeService;

    public ProblemTypeAppService(ProblemTypeRepository problemTypeRepository, ProblemTypeService problemTypeService) {
        this.problemTypeRepository = problemTypeRepository;
        this.problemTypeService = problemTypeService;
    }

    // region problem type
    @HandleServiceException
    public ProblemTypeVO getProblemType(@Min(0) long typeId) {
        return AppServiceUtils.getById(typeId, problemTypeRepository::getProblemType,
                ProblemTypeAssembler.Instance::toProblemTypeVO);
    }

    @HandleServiceException
    public ProblemTypeVO getProblemTypeByCode(@NotBlank String typeCode) {
        return AppServiceUtils.getByText(typeCode, problemTypeRepository::getProblemTypeByCode,
                ProblemTypeAssembler.Instance::toProblemTypeVO);
    }

    @HandleServiceException
    public Collection<ProblemTypeVO> getProblemTypesByName(@NotBlank String typeName) {
        return AppServiceUtils.getListByText(typeName, problemTypeRepository::getProblemTypesByName,
                ProblemTypeAssembler.Instance::toProblemTypeVO);
    }

    @HandleServiceException
    public Collection<ProblemTypeVO> getAvailableProblemTypes() {
        return AppServiceUtils.getList(problemTypeRepository::getAvailableProblemTypes,
                ProblemTypeAssembler.Instance::toProblemTypeVO);
    }

    @HandleServiceException
    public ProblemTypeVO createProblemType(@NotNull CreateProblemTypeCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), problemTypeService::createProblemType,
                ProblemTypeAssembler.Instance::toProblemTypeVO, ProblemTypeAssembler.Instance::fromCreateCommand);

    }

    @HandleServiceException
    public ProblemTypeVO updateProblemType(@NotNull UpdateProblemTypeCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.createOrUpdateBy(command, command.getOperatorId(), problemTypeService::updateProblemType,
                ProblemTypeAssembler.Instance::toProblemTypeVO, ProblemTypeAssembler.Instance::fromUpdateCommand);
    }

    @HandleServiceException
    public boolean deleteProblemType(DeleteCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.delete(command.getId(), command.getOperatorId(), problemTypeService::deleteProblemType);
    }

    @HandleServiceException
    public boolean enableProblemType(EnableCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.delete(command.getId(), command.getOperatorId(), problemTypeService::enableProblemType);
    }

    @HandleServiceException
    public boolean disableProblemType(DisableCommand command) {
        command.setOperatorId(getCurrentUserId());
        return AppServiceUtils.delete(command.getId(), command.getOperatorId(), problemTypeService::disableProblemType);
    }

    @HandleServiceException
    public Collection<QuestionTypeVO> getQuestionTypesByProblemType(@Min(0) long problemTypeId) {
        return AppServiceUtils.getListById(problemTypeId, problemTypeService::getQuestionTypesByProblemType,
                QuestionTypeAssembler.Instance::toQuestionTypeVO);
    }

    // endregion

    // region type relation
    @HandleServiceException
    public boolean bindQuestionType(@NotNull BindTypeRelationCommand command) {
        command.setOperatorId(getCurrentUserId());
        return problemTypeService.bindQuestionType(command.getProblemTypeId(), command.getQuestionTypeId());
    }

    @HandleServiceException
    public boolean unbindQuestionType(@NotNull UnbindTypeRelationCommand command) {
        command.setOperatorId(getCurrentUserId());
        return problemTypeService.unbindQuestionType(command.getProblemTypeId(), command.getQuestionTypeId());
    }
    // endregion
}
